#include <Lucnx/device.h>
#include <Lucnx/string.h>
#include <Lucnx/console.h>
#include <Lucnx/ide.h>
#include <Lucnx/keyboard.h>
#include <Lucnx/timer.h>
#include <Lucnx/tty.h>
#include <Lucnx/debug.h>

#define NR_DEVICES 8

static device_t device_table[NR_DEVICES];

device_t *get_free_device()
{
    for (size_t i = 0; i < NR_DEVICES; i++)
    {
        device_t *device = &device_table[i];
        if (device->type == DEV_NULL)
        {
            return device;
        }
    }
    return NULL;
}

dev_t device_install(
    char *name, void *ptr, void *read, void *write, void *ioctl, device_type_t type, u8 flags)
{
    device_t *device = get_free_device();

    strcpy(device->name, name);
    device->type = type;
    device->flags = flags;
    device->ptr = ptr;

    device->ioctl = ioctl;
    device->read = read;
    device->write = write;

    return device->dev;
}

device_t *device_get(dev_t dev)
{
    device_t *device = &device_table[dev];
    if (device->type == DEV_NULL)
    {
        INFOK("WARNING", "get a null device, dev: %d", dev);
        return NULL;
    }
    return device;
}

dev_t device_search(char *name)
{
    for (size_t i = 0; i < NR_DEVICES; i++)
    {
        device_t *device = device_table + i;
        if (!strcmp(device->name, name))
        {
            return device->dev;
        }
    }
    return EOF;
}

int device_write(dev_t dev, void *ptr, char *buf, int count)
{
    device_t *device = device_get(dev);
    if (device->flags & DF_WRITE)
    {
        return device->write(ptr, buf, count);
    }
    panic("write: not a writing device, dev: %d", dev);
}

int device_read(dev_t dev, void *ptr, char *buf, int count)
{
    device_t *device = device_get(dev);
    if (device->flags & DF_READ)
    {
        return device->read(ptr, buf, count);
    }
    panic("read: not a reading device, dev: %d", dev);
}

int device_ioctl(dev_t dev, void *ptr, char *buf, int count)
{
    device_t *device = device_get(dev);
    if (device->flags & DF_IOCTL)
    {
        return device->ioctl(ptr, buf, count);
    }
    panic("ioctl: bad device, dev: %d", dev);
}

// 打印设备表
void list_devices()
{
    for (size_t i = 0; i < NR_DEVICES; i++)
    {
        device_t *device = &device_table[i];
        if (device->type != DEV_NULL)
        {
            printk("%s ", device->name);
        }
    }
    putchk('\n');
}

void device_init()
{
    for (size_t i = 0; i < NR_DEVICES; i++)
    {
        device_t *device = device_table + i;
        memset(device, 0, sizeof(device_t));
        device->type = DEV_NULL;
        device->dev = i;
    }

    console_init();
    keyboard_init();
    tty_init();
    timer_init();
    ide_init();
}